home *** CD-ROM | disk | FTP | other *** search
/ Whiteline: delta / whiteline CD Series - delta.iso / vision / grafics / programm / ximgtool / encoders.c < prev    next >
C/C++ Source or Header  |  1995-11-25  |  43KB  |  1,555 lines

  1. #include "imgcodec.h"
  2.  
  3. /* Local extension of public image buffer struct for encoding. */
  4.  
  5. typedef struct ibuf
  6. {
  7.   IBUFPUB pub;
  8.   char *line_adr;
  9.   long length;
  10.   long byte_width;    /* Only used in Level-1 encoding. */
  11.   char *image_adr;
  12.   char *image_ptr;    /* Only used in Level-3 encoding. */
  13.   char *ptr_arr[256];
  14.   void (*raw_encode)(struct ibuf *ip);
  15.   void (*user_exit)(void);
  16.   FBUFPUB *output;
  17.   short out_vrc;
  18.   short lines_left;
  19.   FBUFPUB temp;
  20.   char *pbuf;
  21.   char tbuf[4];
  22.   char data[0];
  23. }
  24. IBUF;
  25.  
  26. /* Forward declarations of local functions. */
  27.  
  28. static void level_3_putline(IBUF *ip);
  29. static void level_2_putline(IBUF *ip);
  30. static void level_1_putline(IBUF *ip);
  31.  
  32. static void l_3_p_1_encode(IBUF *ip);
  33. static void l_3_p_2_encode(IBUF *ip);
  34. static void l_2_p_1_encode(IBUF *ip);
  35. static void l_2_p_2_encode(IBUF *ip);
  36. static void l_1_p_1_encode(IBUF *ip);
  37. static void l_1_p_2_encode(IBUF *ip);
  38.  
  39. /* Generic initialization function for encoding.
  40.  * Causes all defined encoding functions to be linked to the caller.
  41.  * Returns a zero pointer if user_malloc failes.
  42.  * Otherwise the returned pointer has to be freed after
  43.  * processing by the 'complement' of user_malloc.
  44.  */
  45.  
  46. IBUFPUB *encode_init(IMG_HEADER *input_header, FBUFPUB *output,
  47.              void *(*user_malloc)(long size),
  48.              void (*user_exit)(void),
  49.              short out_lev, short out_pat)
  50. {
  51.   long byte_width, line_len, buf_len;
  52.   IBUF *image;
  53.  
  54.   byte_width = (input_header->sl_width + 7) >> 3;
  55.   line_len = byte_width * input_header->planes;
  56.   /* Alloc double line buffer for out_vrc handling (one line delay) */
  57.   buf_len = line_len << 1;
  58.   /* For Level-2 we need an additional line buffer for extended vrc
  59.    * handling.
  60.    */
  61.   if (out_lev == 2) buf_len += line_len;
  62.   else if (out_lev != 1)
  63.     /* Level-3 encoder requires a full image buffer. */
  64.     buf_len += line_len * input_header->sl_height;
  65.   image =
  66.     (*user_malloc)(sizeof(IBUF) + buf_len + input_header->pat_run);
  67.   if (image)
  68.   {
  69.     image->line_adr = image->pub.pbuf = image->data;
  70.     image->image_adr = image->data + (line_len << 1);
  71.     image->pub.pat_buf = image->data + buf_len;
  72.     image->pub.bytes_left = line_len;
  73.     image->length = line_len;
  74.     image->byte_width = byte_width;
  75.     image->pub.pat_run = input_header->pat_run;
  76.     image->lines_left = input_header->sl_height;
  77.     image->pub.vrc = 1; image->out_vrc = 0;
  78.     image->output = output; image->user_exit = user_exit;
  79.  
  80.     image->pub.put_line = (void (*)(IBUFPUB *))
  81.       (out_lev == 1 ? level_1_putline :
  82.        out_lev == 2 ? level_2_putline : level_3_putline);
  83.  
  84.     image->raw_encode =
  85.      out_lev == 1
  86.       ? (out_pat == 1 ? l_1_p_1_encode : l_1_p_2_encode)
  87.       :  out_lev == 2
  88.       ? (out_pat == 1 ? l_2_p_1_encode : l_2_p_2_encode)
  89.       : (out_pat == 1 ? l_3_p_1_encode : l_3_p_2_encode);
  90.   }
  91.   return &image->pub;
  92. }
  93.  
  94. /* Here are the special encode initialization functions.
  95.  * The reason for introducing them is, that an application usually
  96.  * needs only one encoder. The programmer has the freedom
  97.  * (or pain ;-) to decide. For instance, a snapshot utility is
  98.  * recommended to use a Level-2 encoder, because extended vrc
  99.  * may provide significant savings over Level-1, and Level-3 could
  100.  * rather fail in memory allocation (if Level-3 is nevertheless
  101.  * desired, there should be at least an alternative Level-2 mode
  102.  * built in to be used in case of Level-3 failing).
  103.  */
  104.  
  105. IBUFPUB *l3p2_encode_init(IMG_HEADER *input_header, FBUFPUB *output,
  106.               void *(*user_malloc)(long size),
  107.               void (*user_exit)(void))
  108. {
  109.   long byte_width, line_len, buf_len;
  110.   IBUF *image;
  111.  
  112.   byte_width = (input_header->sl_width + 7) >> 3;
  113.   line_len = byte_width * input_header->planes;
  114.   /* Alloc double line buffer for out_vrc handling (one line delay) */
  115.   buf_len = line_len << 1;
  116.   /* Level-3 encoder requires a full image buffer. */
  117.   buf_len += line_len * input_header->sl_height;
  118.   image =
  119.     (*user_malloc)(sizeof(IBUF) + buf_len + input_header->pat_run);
  120.   if (image)
  121.   {
  122.     image->line_adr = image->pub.pbuf = image->data;
  123.     image->image_adr = image->data + (line_len << 1);
  124.     image->pub.pat_buf = image->data + buf_len;
  125.     image->pub.bytes_left = line_len;
  126.     image->length = line_len;
  127.     image->pub.pat_run = input_header->pat_run;
  128.     image->lines_left = input_header->sl_height;
  129.     image->pub.vrc = 1; image->out_vrc = 0;
  130.     image->output = output; image->user_exit = user_exit;
  131.     image->pub.put_line = (void (*)(IBUFPUB *))level_3_putline;
  132.     image->raw_encode = l_3_p_2_encode;
  133.   }
  134.   return &image->pub;
  135. }
  136.  
  137. IBUFPUB *l3p1_encode_init(IMG_HEADER *input_header, FBUFPUB *output,
  138.               void *(*user_malloc)(long size),
  139.               void (*user_exit)(void))
  140. {
  141.   long byte_width, line_len, buf_len;
  142.   IBUF *image;
  143.  
  144.   byte_width = (input_header->sl_width + 7) >> 3;
  145.   line_len = byte_width * input_header->planes;
  146.   /* Alloc double line buffer for out_vrc handling (one line delay) */
  147.   buf_len = line_len << 1;
  148.   /* Level-3 encoder requires a full image buffer. */
  149.   buf_len += line_len * input_header->sl_height;
  150.   image =
  151.     (*user_malloc)(sizeof(IBUF) + buf_len + input_header->pat_run);
  152.   if (image)
  153.   {
  154.     image->line_adr = image->pub.pbuf = image->data;
  155.     image->image_adr = image->data + (line_len << 1);
  156.     image->pub.pat_buf = image->data + buf_len;
  157.     image->pub.bytes_left = line_len;
  158.     image->length = line_len;
  159.     image->pub.pat_run = input_header->pat_run;
  160.     image->lines_left = input_header->sl_height;
  161.     image->pub.vrc = 1; image->out_vrc = 0;
  162.     image->output = output; image->user_exit = user_exit;
  163.     image->pub.put_line = (void (*)(IBUFPUB *))level_3_putline;
  164.     image->raw_encode = l_3_p_1_encode;
  165.   }
  166.   return &image->pub;
  167. }
  168.  
  169. IBUFPUB *l2p2_encode_init(IMG_HEADER *input_header, FBUFPUB *output,
  170.               void *(*user_malloc)(long size),
  171.               void (*user_exit)(void))
  172. {
  173.   long byte_width, line_len, buf_len;
  174.   IBUF *image;
  175.  
  176.   byte_width = (input_header->sl_width + 7) >> 3;
  177.   line_len = byte_width * input_header->planes;
  178.   /* Alloc double line buffer for out_vrc handling (one line delay) */
  179.   buf_len = line_len << 1;
  180.   /* For Level-2 we need an additional line buffer for extended vrc
  181.    * handling.
  182.    */
  183.   buf_len += line_len;
  184.   image =
  185.     (*user_malloc)(sizeof(IBUF) + buf_len + input_header->pat_run);
  186.   if (image)
  187.   {
  188.     image->line_adr = image->pub.pbuf = image->data;
  189.     image->image_adr = image->data + (line_len << 1);
  190.     image->pub.pat_buf = image->data + buf_len;
  191.     image->pub.bytes_left = line_len;
  192.     image->length = line_len;
  193.     image->pub.pat_run = input_header->pat_run;
  194.     image->lines_left = input_header->sl_height;
  195.     image->pub.vrc = 1; image->out_vrc = 0;
  196.     image->output = output; image->user_exit = user_exit;
  197.     image->pub.put_line = (void (*)(IBUFPUB *))level_2_putline;
  198.     image->raw_encode = l_2_p_2_encode;
  199.   }
  200.   return &image->pub;
  201. }
  202.  
  203. IBUFPUB *l2p1_encode_init(IMG_HEADER *input_header, FBUFPUB *output,
  204.               void *(*user_malloc)(long size),
  205.               void (*user_exit)(void))
  206. {
  207.   long byte_width, line_len, buf_len;
  208.   IBUF *image;
  209.  
  210.   byte_width = (input_header->sl_width + 7) >> 3;
  211.   line_len = byte_width * input_header->planes;
  212.   /* Alloc double line buffer for out_vrc handling (one line delay) */
  213.   buf_len = line_len << 1;
  214.   /* For Level-2 we need an additional line buffer for extended vrc
  215.    * handling.
  216.    */
  217.   buf_len += line_len;
  218.   image =
  219.     (*user_malloc)(sizeof(IBUF) + buf_len + input_header->pat_run);
  220.   if (image)
  221.   {
  222.     image->line_adr = image->pub.pbuf = image->data;
  223.     image->image_adr = image->data + (line_len << 1);
  224.     image->pub.pat_buf = image->data + buf_len;
  225.     image->pub.bytes_left = line_len;
  226.     image->length = line_len;
  227.     image->pub.pat_run = input_header->pat_run;
  228.     image->lines_left = input_header->sl_height;
  229.     image->pub.vrc = 1; image->out_vrc = 0;
  230.     image->output = output; image->user_exit = user_exit;
  231.     image->pub.put_line = (void (*)(IBUFPUB *))level_2_putline;
  232.     image->raw_encode = l_2_p_1_encode;
  233.   }
  234.   return &image->pub;
  235. }
  236.  
  237. IBUFPUB *l1p2_encode_init(IMG_HEADER *input_header, FBUFPUB *output,
  238.               void *(*user_malloc)(long size),
  239.               void (*user_exit)(void))
  240. {
  241.   long byte_width, line_len, buf_len;
  242.   IBUF *image;
  243.  
  244.   byte_width = (input_header->sl_width + 7) >> 3;
  245.   line_len = byte_width * input_header->planes;
  246.   /* Alloc double line buffer for out_vrc handling (one line delay) */
  247.   buf_len = line_len << 1;
  248.   image =
  249.     (*user_malloc)(sizeof(IBUF) + buf_len + input_header->pat_run);
  250.   if (image)
  251.   {
  252.     image->line_adr = image->pub.pbuf = image->data;
  253.     image->image_adr = image->pub.pat_buf = image->data + buf_len;
  254.     image->pub.bytes_left = line_len;
  255.     image->length = line_len;
  256.     image->byte_width = byte_width;
  257.     image->pub.pat_run = input_header->pat_run;
  258.     image->lines_left = input_header->sl_height;
  259.     image->pub.vrc = 1; image->out_vrc = 0;
  260.     image->output = output; image->user_exit = user_exit;
  261.     image->pub.put_line = (void (*)(IBUFPUB *))level_1_putline;
  262.     image->raw_encode = l_1_p_2_encode;
  263.   }
  264.   return &image->pub;
  265. }
  266.  
  267. IBUFPUB *l1p1_encode_init(IMG_HEADER *input_header, FBUFPUB *output,
  268.               void *(*user_malloc)(long size),
  269.               void (*user_exit)(void))
  270. {
  271.   long byte_width, line_len, buf_len;
  272.   IBUF *image;
  273.  
  274.   byte_width = (input_header->sl_width + 7) >> 3;
  275.   line_len = byte_width * input_header->planes;
  276.   /* Alloc double line buffer for out_vrc handling (one line delay) */
  277.   buf_len = line_len << 1;
  278.   image =
  279.     (*user_malloc)(sizeof(IBUF) + buf_len + input_header->pat_run);
  280.   if (image)
  281.   {
  282.     image->line_adr = image->pub.pbuf = image->data;
  283.     image->image_adr = image->pub.pat_buf = image->data + buf_len;
  284.     image->pub.bytes_left = line_len;
  285.     image->length = line_len;
  286.     image->byte_width = byte_width;
  287.     image->pub.pat_run = input_header->pat_run;
  288.     image->lines_left = input_header->sl_height;
  289.     image->pub.vrc = 1; image->out_vrc = 0;
  290.     image->output = output; image->user_exit = user_exit;
  291.     image->pub.put_line = (void (*)(IBUFPUB *))level_1_putline;
  292.     image->raw_encode = l_1_p_1_encode;
  293.   }
  294.   return &image->pub;
  295. }
  296.  
  297. /* Here come the local functions for encode processing. */
  298.  
  299. static void l_3_p_2_encode(IBUF *ip)
  300. {
  301.   char cdata, c_val, *line_buf, *line_ptr, *endl_buf;
  302.   char **end_ptr, *prp, *vrp, *line_lim0;
  303.   long s_save, p_save, v_save, buf_offs;
  304.   FBUFPUB *output;
  305.  
  306.   line_ptr = line_buf = ip->image_adr;
  307.   ip->image_adr = endl_buf = ip->image_ptr;
  308.   buf_offs = -ip->length; end_ptr = ip->ptr_arr;
  309.   output = ip->output;
  310.   do
  311.   { /* Level-3 output loop equals Level-2
  312.      * (different initializations).
  313.      * So look at the below Level-2 code for comments.
  314.      */
  315.     char *orig_ptr = line_ptr;
  316.     start:
  317.     line_lim0 = orig_ptr + 256;
  318.     if (line_lim0 > endl_buf) line_lim0 = endl_buf;
  319.     do
  320.     { char *start_ptr = line_buf;
  321.       s_save = -1;
  322.       if ((cdata = *line_buf) == 0 || cdata == -1)
  323.       {
  324.     char *line_lim = line_buf + 127;
  325.     do
  326.     { if (*line_buf != cdata)
  327.       {
  328.         cdata = ~cdata;
  329.         if (*line_buf != cdata) break;
  330.         line_lim = line_buf;
  331.       }
  332.       if (line_buf >= line_lim)
  333.       {
  334.         s_save -= 1; line_lim += 127;
  335.     } }
  336.     while (++line_buf < endl_buf);
  337.     s_save += line_buf - start_ptr;
  338.     if (start_ptr != orig_ptr && line_buf < line_lim0)
  339.       s_save -= 2;
  340.     line_buf = start_ptr; cdata = *line_buf;
  341.       }
  342.       if (line_buf < endl_buf - 1)
  343.       {
  344.     char *line_lim = line_buf + 255 * 2;
  345.     if (line_lim > endl_buf) line_lim = endl_buf;
  346.     --line_lim;
  347.     c_val = line_buf[1];
  348.     do line_buf += 2;
  349.     while (line_buf < line_lim &&
  350.            line_buf[0] == cdata &&
  351.            line_buf[1] == c_val);
  352.       }
  353.       prp = line_buf; line_buf = start_ptr;
  354.       p_save = (prp - line_buf) - 4;
  355.       if (line_buf != orig_ptr && prp < line_lim0) p_save -= 2;
  356.       v_save = -3;
  357.       if (cdata == line_buf[buf_offs])
  358.       {
  359.     char *line_lim = line_buf + 255;
  360.     if (line_lim > endl_buf) line_lim = endl_buf;
  361.     do line_buf++;
  362.     while (line_buf < line_lim &&
  363.            line_buf[0] == line_buf[buf_offs]);
  364.     vrp = line_buf; line_buf = start_ptr;
  365.     v_save += vrp - line_buf;
  366.     if (line_buf != orig_ptr)
  367.     {
  368.       if (vrp < line_lim0)
  369.       {
  370.         if ((cdata = *vrp) == 0 || cdata == -1)
  371.         {
  372.           int limit = 3; line_lim = vrp;
  373.           do
  374.         if (*line_lim != cdata)
  375.         {
  376.           cdata = ~cdata;
  377.           if (*line_lim != cdata)
  378.           {
  379.             v_save -= 2; break;
  380.         } }
  381.         else if (--limit == 0) break;
  382.           while (++line_lim < line_lim0);
  383.         }
  384.         else v_save -= 2;
  385.         cdata = *line_buf;
  386.       }
  387.       if (v_save >= 0 && v_save > p_save && v_save > s_save)
  388.       {
  389.         line_lim = line_buf + 2;
  390.         if ((cdata = c_val) == 0 || cdata == -1)
  391.         {
  392.           do if (line_lim == vrp) goto ex;
  393.           while (*line_lim++ == cdata);
  394.           --line_lim;
  395.           if (line_lim <= line_buf + 128 &&
  396.           vrp < line_lim + 127 && vrp < endl_buf)
  397.           {
  398.         c_val = ~c_val;
  399.         do if (line_lim > vrp) goto ex;
  400.         while (*line_lim++ == c_val);
  401.         } }
  402.         else if (line_lim <= line_lim0 &&
  403.              ((cdata = *line_lim++) == 0 || cdata == -1)
  404.              && vrp < line_lim + 126 && vrp < endl_buf)
  405.           do
  406.         if (line_lim > vrp)
  407.         {
  408.           line_buf++;
  409.           ex: s_save = v_save; line_buf++; break;
  410.         }
  411.           while (*line_lim++ == cdata);
  412.     } } } }
  413.     while (s_save < 0 && p_save < 0 && v_save < 0 &&
  414.        ++line_buf < line_lim0);
  415.     if (line_buf != line_ptr)
  416.     {
  417.       if (line_buf < line_lim0)
  418.       {
  419.     *end_ptr++ = endl_buf;
  420.     endl_buf = line_buf;
  421.     line_buf = line_ptr;
  422.     goto start;
  423.       }
  424.       FPUTC(output, 0x80);
  425.       FPUTC(output, (char)(line_buf - line_ptr));
  426.       do FPUTC(output, *line_ptr++);
  427.       while (line_ptr < line_buf);
  428.     }
  429.     if (s_save >= 0 && s_save >= p_save && s_save >= v_save)
  430.     {
  431.       char *line_lim = line_buf + 127;
  432.       if (line_lim > endl_buf) line_lim = endl_buf;
  433.       do line_buf++;
  434.       while (line_buf < line_lim && *line_buf == cdata);
  435.       cdata <<= 7;
  436.       FPUTC(output, cdata | (char)(line_buf - line_ptr));
  437.       line_ptr = line_buf;
  438.     }
  439.     else if (p_save >= 0 && p_save >= v_save)
  440.     {
  441.       line_buf = prp;
  442.       FPUTC(output, 0);
  443.       FPUTC(output, (char)((line_buf - line_ptr) >> 1));
  444.       FPUTC(output, cdata);
  445.       FPUTC(output, c_val);
  446.       line_ptr = line_buf;
  447.     }
  448.     else if (v_save >= 0)
  449.     {
  450.       line_buf = vrp;
  451.       FPUTC(output, 0);
  452.       FPUTC(output, 0);
  453.       FPUTC(output, (char)(line_buf - line_ptr) - 1);
  454.       line_ptr = line_buf;
  455.     }
  456.     if (end_ptr != ip->ptr_arr)
  457.     {
  458.       endl_buf = *--end_ptr; goto start;
  459.   } }
  460.   while (line_buf < endl_buf);
  461. }
  462.  
  463. static void l_3_p_1_encode(IBUF *ip)
  464. {
  465.   char cdata, *line_buf, *line_ptr, *endl_buf;
  466.   char **end_ptr, *prp, *vrp, *line_lim0;
  467.   long s_save, p_save, v_save, buf_offs;
  468.   FBUFPUB *output;
  469.  
  470.   line_ptr = line_buf = ip->image_adr;
  471.   ip->image_adr = endl_buf = ip->image_ptr;
  472.   buf_offs = -ip->length; end_ptr = ip->ptr_arr;
  473.   output = ip->output;
  474.   do
  475.   { /* Level-3 output loop equals Level-2
  476.      * (different initializations).
  477.      * So look at the below Level-2 code for comments.
  478.      */
  479.     char *orig_ptr = line_ptr;
  480.     start:
  481.     line_lim0 = orig_ptr + 256;
  482.     if (line_lim0 > endl_buf) line_lim0 = endl_buf;
  483.     do
  484.     { char *start_ptr = line_buf;
  485.       s_save = -1;
  486.       if ((cdata = *line_buf) == 0 || cdata == -1)
  487.       {
  488.     char *line_lim = line_buf + 127;
  489.     do
  490.     { if (*line_buf != cdata)
  491.       {
  492.         cdata = ~cdata;
  493.         if (*line_buf != cdata) break;
  494.         line_lim = line_buf;
  495.       }
  496.       if (line_buf >= line_lim)
  497.       {
  498.         s_save -= 1; line_lim += 127;
  499.     } }
  500.     while (++line_buf < endl_buf);
  501.     s_save += line_buf - start_ptr;
  502.     if (start_ptr != orig_ptr && line_buf < line_lim0)
  503.       s_save -= 2;
  504.     line_buf = start_ptr; cdata = *line_buf;
  505.       }
  506.       {
  507.     char *line_lim = line_buf + 255;
  508.     if (line_lim > endl_buf) line_lim = endl_buf;
  509.     do line_buf++;
  510.     while (line_buf < line_lim && *line_buf == cdata);
  511.     prp = line_buf; line_buf = start_ptr;
  512.     p_save = (prp - line_buf) - 3;
  513.     if (line_buf != orig_ptr && prp < line_lim0) p_save -= 2;
  514.       }
  515.       v_save = -3;
  516.       if (cdata == line_buf[buf_offs])
  517.       {
  518.     char *line_lim = line_buf + 255;
  519.     if (line_lim > endl_buf) line_lim = endl_buf;
  520.     do line_buf++;
  521.     while (line_buf < line_lim &&
  522.            line_buf[0] == line_buf[buf_offs]);
  523.     vrp = line_buf; line_buf = start_ptr;
  524.     v_save += vrp - line_buf;
  525.     if (line_buf != orig_ptr)
  526.     {
  527.       if (vrp < line_lim0)
  528.       {
  529.         if ((cdata = *vrp) == 0 || cdata == -1)
  530.         {
  531.           int limit = 3; line_lim = vrp;
  532.           do
  533.         if (*line_lim != cdata)
  534.         {
  535.           cdata = ~cdata;
  536.           if (*line_lim != cdata)
  537.           {
  538.             v_save -= 2; break;
  539.         } }
  540.         else if (--limit == 0) break;
  541.           while (++line_lim < line_lim0);
  542.         }
  543.         else v_save -= 2;
  544.         cdata = *line_buf;
  545.       }
  546.       if (v_save >= 0 && v_save > p_save && v_save > s_save)
  547.       {
  548.         line_lim = line_buf + 2;
  549.         if ((cdata = line_buf[1]) == 0 || cdata == -1)
  550.         {
  551.           do if (line_lim == vrp) goto ex;
  552.           while (*line_lim++ == cdata);
  553.           --line_lim;
  554.           if (line_lim <= line_buf + 128 &&
  555.           vrp < line_lim + 127 && vrp < endl_buf)
  556.           {
  557.         char c_val = cdata; c_val = ~c_val;
  558.         do if (line_lim > vrp) goto ex;
  559.         while (*line_lim++ == c_val);
  560.         } }
  561.         else if (line_lim <= line_lim0 &&
  562.              ((cdata = *line_lim++) == 0 || cdata == -1)
  563.              && vrp < line_lim + 126 && vrp < endl_buf)
  564.           do
  565.         if (line_lim > vrp)
  566.         {
  567.           line_buf++;
  568.           ex: s_save = v_save; line_buf++; break;
  569.         }
  570.           while (*line_lim++ == cdata);
  571.     } } } }
  572.     while (s_save < 0 && p_save < 0 && v_save < 0 &&
  573.        ++line_buf < line_lim0);
  574.     if (line_buf != line_ptr)
  575.     {
  576.       if (line_buf < line_lim0)
  577.       {
  578.     *end_ptr++ = endl_buf;
  579.     endl_buf = line_buf;
  580.     line_buf = line_ptr;
  581.     goto start;
  582.       }
  583.       FPUTC(output, 0x80);
  584.       FPUTC(output, (char)(line_buf - line_ptr));
  585.       do FPUTC(output, *line_ptr++);
  586.       while (line_ptr < line_buf);
  587.     }
  588.     if (s_save >= 0 && s_save >= p_save && s_save >= v_save)
  589.     {
  590.       char *line_lim = line_buf + 127;
  591.       if (line_lim > endl_buf) line_lim = endl_buf;
  592.       do line_buf++;
  593.       while (line_buf < line_lim && *line_buf == cdata);
  594.       cdata <<= 7;
  595.       FPUTC(output, cdata | (char)(line_buf - line_ptr));
  596.       line_ptr = line_buf;
  597.     }
  598.     else if (p_save >= 0 && p_save >= v_save)
  599.     {
  600.       line_buf = prp;
  601.       FPUTC(output, 0);
  602.       FPUTC(output, (char)(line_buf - line_ptr));
  603.       FPUTC(output, cdata);
  604.       line_ptr = line_buf;
  605.     }
  606.     else if (v_save >= 0)
  607.     {
  608.       line_buf = vrp;
  609.       FPUTC(output, 0);
  610.       FPUTC(output, 0);
  611.       FPUTC(output, (char)(line_buf - line_ptr) - 1);
  612.       line_ptr = line_buf;
  613.     }
  614.     if (end_ptr != ip->ptr_arr)
  615.     {
  616.       endl_buf = *--end_ptr; goto start;
  617.   } }
  618.   while (line_buf < endl_buf);
  619. }
  620.  
  621. static void level_3_putline(IBUF *ip)
  622. {
  623.   char *line_buf, *line_ptr, *endl_buf;
  624.   FBUFPUB *output;
  625.  
  626.   line_buf = ip->line_adr;
  627.   endl_buf = ip->pub.pbuf;
  628.   output = ip->output;
  629.  
  630.   if (ip->out_vrc == 0)
  631.   {
  632.     if (ip->pub.bytes_left) return;
  633.     line_ptr = endl_buf;
  634.     /*
  635.      * Make a complement copy of the first line. This is a trick
  636.      * to avoid special casing extended vrc checking for the first
  637.      * line in the raw encoder.
  638.      */
  639.     do *line_ptr++ = ~*line_buf++;
  640.     while (line_buf < endl_buf);
  641.     goto mark3;
  642.   }
  643.   if (ip->pub.bytes_left)
  644.   {
  645.     ip->pub.pbuf += ip->pub.bytes_left;
  646.     ip->pub.bytes_left = 0;
  647.     if (ip->out_vrc - 1)
  648.       if ((ip->out_vrc - 1) * ip->length < 256)
  649.       {
  650.     line_ptr = ip->image_ptr;
  651.     ip->image_ptr += (ip->out_vrc - 1) * ip->length;
  652.     line_buf = line_ptr;
  653.     line_ptr += ip->length;
  654.     do *line_ptr++ = *line_buf++;
  655.     while (line_buf < ip->image_ptr);
  656.       }
  657.       else
  658.       {
  659.     if (ip->image_ptr != ip->image_adr)
  660.       (*ip->raw_encode)(ip);
  661.     FPUTC(output, 0); FPUTC(output, 0);
  662.     FPUTC(output, 0xFF);
  663.     FPUTC(output, (char)ip->out_vrc);
  664.       }
  665.     ip->out_vrc = 0;
  666.     ip->image_ptr += ip->length;
  667.     (*ip->raw_encode)(ip);
  668.     ip->pub.pbuf = ip->line_adr;
  669.     ip->pub.bytes_left = ip->length;
  670.     return;
  671.   }
  672.   line_ptr = ip->image_ptr;
  673.   do
  674.     if (*line_ptr++ != *line_buf++)
  675.     {
  676.       if (ip->out_vrc - 1)
  677.       {
  678.     if ((ip->out_vrc - 1) * ip->length >= 256)
  679.       goto mark1;
  680.     line_ptr = ip->image_ptr;
  681.     ip->image_ptr += (ip->out_vrc - 1) * ip->length;
  682.     line_buf = line_ptr;
  683.     line_ptr += ip->length;
  684.     do *line_ptr++ = *line_buf++;
  685.     while (line_buf < ip->image_ptr);
  686.       }
  687.       goto mark2;
  688.     }
  689.   while (line_buf < endl_buf);
  690.  
  691.   do
  692.   { if (ip->out_vrc == 256)
  693.     {
  694.       mark1:
  695.       if (ip->image_ptr != ip->image_adr)
  696.     (*ip->raw_encode)(ip);
  697.       FPUTC(output, 0); FPUTC(output, 0);
  698.       FPUTC(output, 0xFF);
  699.       FPUTC(output, (char)ip->out_vrc);
  700.       mark2:
  701.       ip->out_vrc = 0;
  702.       line_ptr = ip->image_ptr;
  703.       line_ptr += ip->length;
  704.       mark3:
  705.       line_buf = ip->line_adr;
  706.       ip->image_ptr = line_ptr;
  707.       do *line_ptr++ = *line_buf++;
  708.       while (line_buf < endl_buf);
  709.     }
  710.     ip->out_vrc++;
  711.     if (--ip->lines_left <= 0)
  712.     {
  713.       if (ip->out_vrc - 1)
  714.     if ((ip->out_vrc - 1) * ip->length < 256)
  715.     {
  716.       line_ptr = ip->image_ptr;
  717.       ip->image_ptr += (ip->out_vrc - 1) * ip->length;
  718.       line_buf = line_ptr;
  719.       line_ptr += ip->length;
  720.       do *line_ptr++ = *line_buf++;
  721.       while (line_buf < ip->image_ptr);
  722.     }
  723.     else
  724.     {
  725.       if (ip->image_ptr != ip->image_adr)
  726.         (*ip->raw_encode)(ip);
  727.       FPUTC(output, 0); FPUTC(output, 0);
  728.       FPUTC(output, 0xFF);
  729.       FPUTC(output, (char)ip->out_vrc);
  730.     }
  731.       ip->out_vrc = 0;
  732.       ip->image_ptr += ip->length;
  733.       (*ip->raw_encode)(ip);
  734.       ip->pub.pbuf = ip->line_adr;
  735.       ip->pub.bytes_left = ip->length;
  736.       (*ip->user_exit)();
  737.   } }
  738.   while (--ip->pub.vrc);
  739.   ip->pub.vrc++;
  740.  
  741.   ip->pub.pbuf = ip->line_adr; ip->pub.bytes_left = ip->length;
  742. }
  743.  
  744. static void put_vrc(FBUFPUB *output)
  745. {
  746.   IBUF *ip;
  747.   char *p;
  748.  
  749.   ip = (IBUF *)output->pbuf;
  750.   *output = ip[-1].temp;
  751.   FPUTC(output, 0);
  752.   FPUTC(output, 0);
  753.   FPUTC(output, 0xFF);
  754.   FPUTC(output, (char)ip[-1].out_vrc);
  755.   ip[-1].out_vrc = 1;
  756.   p = ip[-1].pbuf;
  757.   do FPUTC(output, *p++);
  758.   while (p < (char *)ip);
  759. }
  760.  
  761. static void l_2_p_2_encode(IBUF *ip)
  762. {
  763.   char cdata, c_val, *line_buf, *line_ptr, *endl_buf;
  764.   char **end_ptr, *prp, *vrp, *line_lim0;
  765.   long s_save, p_save, v_save, buf_offs;
  766.   FBUFPUB *output;
  767.  
  768.   output = ip->output; buf_offs = ip->length;
  769.   if (ip->out_vrc != 1)
  770.     if (ip->out_vrc != 2 || buf_offs >= 256)
  771.     {
  772.       long limit = 1;
  773.       ip->temp = *output;
  774.       switch (ip->out_vrc)
  775.       {
  776.     case 2: limit += 2;
  777.     case 3:
  778.     case 4: limit += 1;
  779.       }
  780.       output->pbuf = ip->pbuf = ip->data - limit;
  781.       output->bytes_left = limit;
  782.       output->data_func = put_vrc;
  783.     }
  784.   endl_buf = ip->image_adr; end_ptr = ip->ptr_arr;
  785.   do
  786.   { /* OK, here's the heart of the Level-2 encoder...
  787.      * The outer loop (within full-line loop) is set up for
  788.      * simple (uncompressed) bytestring handling.
  789.      * "line_ptr" points to next byte to write, "line_buf"
  790.      * is a preview pointer to check for possible _s_olid,
  791.      * _p_attern, or _v_ertical run compression.
  792.      */
  793.     line_ptr = line_buf = ip->pub.pbuf;
  794.     do
  795.     { /* "line_lim0" is set as limit for bytestring handler.
  796.        * NOTE: The offset 256 is the maximum Level-2 bytestring
  797.        * counter, which results in a zero byte value if reached.
  798.        * For Level-1 (compatibility) the maximum offset is 255.
  799.        */
  800.       char *orig_ptr = line_ptr;
  801.       start:
  802.       line_lim0 = orig_ptr + 256;
  803.       if (line_lim0 > endl_buf) line_lim0 = endl_buf;
  804.       do
  805.       { char *start_ptr = line_buf;
  806.     s_save = -1;
  807.     if ((cdata = *line_buf) == 0 || cdata == -1)
  808.     {
  809.       char *line_lim = line_buf + 127;
  810.       do
  811.       { if (*line_buf != cdata)
  812.         {
  813.           cdata = ~cdata;
  814.           if (*line_buf != cdata) break;
  815.           line_lim = line_buf;
  816.         }
  817.         if (line_buf >= line_lim)
  818.         {
  819.           s_save -= 1; line_lim += 127;
  820.       } }
  821.       while (++line_buf < endl_buf);
  822.       s_save += line_buf - start_ptr;
  823.       if (start_ptr != orig_ptr && line_buf < line_lim0)
  824.         s_save -= 2;
  825.       line_buf = start_ptr; cdata = *line_buf;
  826.     }
  827.     if (line_buf < endl_buf - 1)
  828.     {
  829.       char *line_lim = line_buf + 255 * 2;
  830.       if (line_lim > endl_buf) line_lim = endl_buf;
  831.       --line_lim;
  832.       c_val = line_buf[1];
  833.       do line_buf += 2;
  834.       while (line_buf < line_lim &&
  835.          line_buf[0] == cdata &&
  836.          line_buf[1] == c_val);
  837.     }
  838.     prp = line_buf; line_buf = start_ptr;
  839.     p_save = (prp - line_buf) - 4;
  840.     if (line_buf != orig_ptr && prp < line_lim0) p_save -= 2;
  841.     v_save = -3;
  842.     if (cdata == line_buf[buf_offs])
  843.     {
  844.       char *line_lim = line_buf + 255;
  845.       if (line_lim > endl_buf) line_lim = endl_buf;
  846.       do line_buf++;
  847.       while (line_buf < line_lim &&
  848.          line_buf[0] == line_buf[buf_offs]);
  849.       vrp = line_buf; line_buf = start_ptr;
  850.       v_save += vrp - line_buf;
  851.       if (line_buf != orig_ptr)
  852.       {
  853.         if (vrp < line_lim0)
  854.         {
  855.           if ((cdata = *vrp) == 0 || cdata == -1)
  856.           {
  857.         int limit = 3; line_lim = vrp;
  858.         do
  859.           if (*line_lim != cdata)
  860.           {
  861.             cdata = ~cdata;
  862.             if (*line_lim != cdata)
  863.             {
  864.               v_save -= 2; break;
  865.           } }
  866.           else if (--limit == 0) break;
  867.         while (++line_lim < line_lim0);
  868.           }
  869.           else v_save -= 2;
  870.           cdata = *line_buf;
  871.         }
  872.         if (v_save >= 0 && v_save > p_save && v_save > s_save)
  873.         {
  874.           line_lim = line_buf + 2;
  875.           if ((cdata = c_val) == 0 || cdata == -1)
  876.           {
  877.         do if (line_lim == vrp) goto ex;
  878.         while (*line_lim++ == cdata);
  879.         --line_lim;
  880.         if (line_lim <= line_buf + 128 &&
  881.             vrp < line_lim + 127 && vrp < endl_buf)
  882.         {
  883.           c_val = ~c_val;
  884.           do if (line_lim > vrp) goto ex;
  885.           while (*line_lim++ == c_val);
  886.           } }
  887.           else if (line_lim <= line_lim0 &&
  888.                ((cdata = *line_lim++) == 0 || cdata == -1)
  889.                && vrp < line_lim + 126 && vrp < endl_buf)
  890.         do
  891.           if (line_lim > vrp)
  892.           {
  893.             line_buf++;
  894.             ex: s_save = v_save; line_buf++; break;
  895.           }
  896.         while (*line_lim++ == cdata);
  897.       } } } }
  898.       while (s_save < 0 && p_save < 0 && v_save < 0 &&
  899.          ++line_buf < line_lim0);
  900.       if (line_buf != line_ptr)
  901.       {
  902.     if (line_buf < line_lim0)
  903.     {
  904.       *end_ptr++ = endl_buf;
  905.       endl_buf = line_buf;
  906.       line_buf = line_ptr;
  907.       goto start;
  908.     }
  909.     FPUTC(output, 0x80);
  910.     FPUTC(output, (char)(line_buf - line_ptr));
  911.     do FPUTC(output, *line_ptr++);
  912.     while (line_ptr < line_buf);
  913.       }
  914.       if (s_save >= 0 && s_save >= p_save && s_save >= v_save)
  915.       {
  916.     char *line_lim = line_buf + 127;
  917.     if (line_lim > endl_buf) line_lim = endl_buf;
  918.     do line_buf++;
  919.     while (line_buf < line_lim && *line_buf == cdata);
  920.     cdata <<= 7;
  921.     FPUTC(output, cdata | (char)(line_buf - line_ptr));
  922.     line_ptr = line_buf;
  923.       }
  924.       else if (p_save >= 0 && p_save >= v_save)
  925.       {
  926.     line_buf = prp;
  927.     FPUTC(output, 0);
  928.     FPUTC(output, (char)((line_buf - line_ptr) >> 1));
  929.     FPUTC(output, cdata);
  930.     FPUTC(output, c_val);
  931.     line_ptr = line_buf;
  932.       }
  933.       else if (v_save >= 0)
  934.       {
  935.     line_buf = vrp;
  936.     FPUTC(output, 0);
  937.     FPUTC(output, 0);
  938.     FPUTC(output, (char)(line_buf - line_ptr) - 1);
  939.     line_ptr = line_buf;
  940.       }
  941.       if (end_ptr != ip->ptr_arr)
  942.       {
  943.     endl_buf = *--end_ptr; goto start;
  944.     } }
  945.     while (line_buf < endl_buf);
  946.  
  947.     line_buf = ip->pub.pbuf;
  948.     line_ptr = endl_buf;
  949.     do *line_ptr++ = *line_buf++;
  950.     while (line_buf < endl_buf);
  951.  
  952.     if (ip->out_vrc != 1)
  953.       if (ip->out_vrc != 2 || buf_offs >= 256)
  954.       {
  955.     line_buf = output->pbuf;
  956.     *output = ip->temp;
  957.     do
  958.     { line_ptr = ip->pbuf;
  959.       do FPUTC(output, *line_ptr++);
  960.       while (line_ptr < line_buf);
  961.     }
  962.     while (--ip->out_vrc);
  963.     return;
  964.   }   }
  965.   while (--ip->out_vrc);
  966. }
  967.  
  968. static void l_2_p_1_encode(IBUF *ip)
  969. {
  970.   char cdata, *line_buf, *line_ptr, *endl_buf;
  971.   char **end_ptr, *prp, *vrp, *line_lim0;
  972.   long s_save, p_save, v_save, buf_offs;
  973.   FBUFPUB *output;
  974.  
  975.   output = ip->output; buf_offs = ip->length;
  976.   if (ip->out_vrc != 1)
  977.     if (ip->out_vrc != 2 || buf_offs >= 256)
  978.     {
  979.       long limit = 1;
  980.       ip->temp = *output;
  981.       switch (ip->out_vrc)
  982.       {
  983.     case 2: limit += 2;
  984.     case 3:
  985.     case 4: limit += 1;
  986.       }
  987.       output->pbuf = ip->pbuf = ip->data - limit;
  988.       output->bytes_left = limit;
  989.       output->data_func = put_vrc;
  990.     }
  991.   endl_buf = ip->image_adr; end_ptr = ip->ptr_arr;
  992.   do
  993.   { /* OK, here's the heart of the Level-2 encoder...
  994.      * The outer loop (within full-line loop) is set up for
  995.      * simple (uncompressed) bytestring handling.
  996.      * "line_ptr" points to next byte to write, "line_buf"
  997.      * is a preview pointer to check for possible _s_olid,
  998.      * _p_attern, or _v_ertical run compression.
  999.      */
  1000.     line_ptr = line_buf = ip->pub.pbuf;
  1001.     do
  1002.     { /* "line_lim0" is set as limit for bytestring handler.
  1003.        * NOTE: The offset 256 is the maximum Level-2 bytestring
  1004.        * counter, which results in a zero byte value if reached.
  1005.        * For Level-1 (compatibility) the maximum offset is 255.
  1006.        */
  1007.       char *orig_ptr = line_ptr;
  1008.       start:
  1009.       line_lim0 = orig_ptr + 256;
  1010.       if (line_lim0 > endl_buf) line_lim0 = endl_buf;
  1011.       do
  1012.       { char *start_ptr = line_buf;
  1013.     s_save = -1;
  1014.     if ((cdata = *line_buf) == 0 || cdata == -1)
  1015.     {
  1016.       char *line_lim = line_buf + 127;
  1017.       do
  1018.       { if (*line_buf != cdata)
  1019.         {
  1020.           cdata = ~cdata;
  1021.           if (*line_buf != cdata) break;
  1022.           line_lim = line_buf;
  1023.         }
  1024.         if (line_buf >= line_lim)
  1025.         {
  1026.           s_save -= 1; line_lim += 127;
  1027.       } }
  1028.       while (++line_buf < endl_buf);
  1029.       s_save += line_buf - start_ptr;
  1030.       if (start_ptr != orig_ptr && line_buf < line_lim0)
  1031.         s_save -= 2;
  1032.       line_buf = start_ptr; cdata = *line_buf;
  1033.     }
  1034.     {
  1035.       char *line_lim = line_buf + 255;
  1036.       if (line_lim > endl_buf) line_lim = endl_buf;
  1037.       do line_buf++;
  1038.       while (line_buf < line_lim && *line_buf == cdata);
  1039.       prp = line_buf; line_buf = start_ptr;
  1040.       p_save = (prp - line_buf) - 3;
  1041.       if (line_buf != orig_ptr && prp < line_lim0) p_save -= 2;
  1042.     }
  1043.     v_save = -3;
  1044.     if (cdata == line_buf[buf_offs])
  1045.     {
  1046.       char *line_lim = line_buf + 255;
  1047.       if (line_lim > endl_buf) line_lim = endl_buf;
  1048.       do line_buf++;
  1049.       while (line_buf < line_lim &&
  1050.          line_buf[0] == line_buf[buf_offs]);
  1051.       vrp = line_buf; line_buf = start_ptr;
  1052.       v_save += vrp - line_buf;
  1053.       if (line_buf != orig_ptr)
  1054.       {
  1055.         if (vrp < line_lim0)
  1056.         {
  1057.           if ((cdata = *vrp) == 0 || cdata == -1)
  1058.           {
  1059.         int limit = 3; line_lim = vrp;
  1060.         do
  1061.           if (*line_lim != cdata)
  1062.           {
  1063.             cdata = ~cdata;
  1064.             if (*line_lim != cdata)
  1065.             {
  1066.               v_save -= 2; break;
  1067.           } }
  1068.           else if (--limit == 0) break;
  1069.         while (++line_lim < line_lim0);
  1070.           }
  1071.           else v_save -= 2;
  1072.           cdata = *line_buf;
  1073.         }
  1074.         if (v_save >= 0 && v_save > p_save && v_save > s_save)
  1075.         {
  1076.           line_lim = line_buf + 2;
  1077.           if ((cdata = line_buf[1]) == 0 || cdata == -1)
  1078.           {
  1079.         do if (line_lim == vrp) goto ex;
  1080.         while (*line_lim++ == cdata);
  1081.         --line_lim;
  1082.         if (line_lim <= line_buf + 128 &&
  1083.             vrp < line_lim + 127 && vrp < endl_buf)
  1084.         {
  1085.           char c_val = cdata; c_val = ~c_val;
  1086.           do if (line_lim > vrp) goto ex;
  1087.           while (*line_lim++ == c_val);
  1088.           } }
  1089.           else if (line_lim <= line_lim0 &&
  1090.                ((cdata = *line_lim++) == 0 || cdata == -1)
  1091.                && vrp < line_lim + 126 && vrp < endl_buf)
  1092.         do
  1093.           if (line_lim > vrp)
  1094.           {
  1095.             line_buf++;
  1096.             ex: s_save = v_save; line_buf++; break;
  1097.           }
  1098.         while (*line_lim++ == cdata);
  1099.       } } } }
  1100.       while (s_save < 0 && p_save < 0 && v_save < 0 &&
  1101.          ++line_buf < line_lim0);
  1102.       if (line_buf != line_ptr)
  1103.       {
  1104.     if (line_buf < line_lim0)
  1105.     {
  1106.       *end_ptr++ = endl_buf;
  1107.       endl_buf = line_buf;
  1108.       line_buf = line_ptr;
  1109.       goto start;
  1110.     }
  1111.     FPUTC(output, 0x80);
  1112.     FPUTC(output, (char)(line_buf - line_ptr));
  1113.     do FPUTC(output, *line_ptr++);
  1114.     while (line_ptr < line_buf);
  1115.       }
  1116.       if (s_save >= 0 && s_save >= p_save && s_save >= v_save)
  1117.       {
  1118.     char *line_lim = line_buf + 127;
  1119.     if (line_lim > endl_buf) line_lim = endl_buf;
  1120.     do line_buf++;
  1121.     while (line_buf < line_lim && *line_buf == cdata);
  1122.     cdata <<= 7;
  1123.     FPUTC(output, cdata | (char)(line_buf - line_ptr));
  1124.     line_ptr = line_buf;
  1125.       }
  1126.       else if (p_save >= 0 && p_save >= v_save)
  1127.       {
  1128.     line_buf = prp;
  1129.     FPUTC(output, 0);
  1130.     FPUTC(output, (char)(line_buf - line_ptr));
  1131.     FPUTC(output, cdata);
  1132.     line_ptr = line_buf;
  1133.       }
  1134.       else if (v_save >= 0)
  1135.       {
  1136.     line_buf = vrp;
  1137.     FPUTC(output, 0);
  1138.     FPUTC(output, 0);
  1139.     FPUTC(output, (char)(line_buf - line_ptr) - 1);
  1140.     line_ptr = line_buf;
  1141.       }
  1142.       if (end_ptr != ip->ptr_arr)
  1143.       {
  1144.     endl_buf = *--end_ptr; goto start;
  1145.     } }
  1146.     while (line_buf < endl_buf);
  1147.  
  1148.     line_buf = ip->pub.pbuf;
  1149.     line_ptr = endl_buf;
  1150.     do *line_ptr++ = *line_buf++;
  1151.     while (line_buf < endl_buf);
  1152.  
  1153.     if (ip->out_vrc != 1)
  1154.       if (ip->out_vrc != 2 || buf_offs >= 256)
  1155.       {
  1156.     line_buf = output->pbuf;
  1157.     *output = ip->temp;
  1158.     do
  1159.     { line_ptr = ip->pbuf;
  1160.       do FPUTC(output, *line_ptr++);
  1161.       while (line_ptr < line_buf);
  1162.     }
  1163.     while (--ip->out_vrc);
  1164.     return;
  1165.   }   }
  1166.   while (--ip->out_vrc);
  1167. }
  1168.  
  1169. static void level_2_putline(IBUF *ip)
  1170. {
  1171.   char *line_buf, *line_ptr, *endl_buf;
  1172.  
  1173.   line_buf = ip->line_adr;
  1174.   endl_buf = ip->pub.pbuf;
  1175.  
  1176.   if (ip->out_vrc == 0)
  1177.   {
  1178.     if (ip->pub.bytes_left) return;
  1179.     line_ptr = ip->image_adr;
  1180.     /*
  1181.      * Make a complement copy of the first line. This is a trick
  1182.      * to avoid special casing extended vrc checking for the first
  1183.      * line in the raw encoder.
  1184.      */
  1185.     do *line_ptr++ = ~*line_buf++;
  1186.     while (line_buf < endl_buf);
  1187.     line_buf = ip->line_adr;
  1188.     line_ptr = endl_buf;
  1189.   }
  1190.   else
  1191.   {
  1192.     if (ip->pub.bytes_left)
  1193.     {
  1194.       ip->pub.pbuf += ip->pub.bytes_left;
  1195.       ip->pub.bytes_left = 0;
  1196.       (*ip->raw_encode)(ip);
  1197.       ip->pub.pbuf = ip->line_adr;
  1198.       ip->pub.bytes_left = ip->length;
  1199.       return;
  1200.     }
  1201.     line_ptr = endl_buf;
  1202.     do
  1203.     { if (*line_ptr != *line_buf)
  1204.       {
  1205.     (*ip->raw_encode)(ip);
  1206.     break;
  1207.       }
  1208.       line_ptr++; line_buf++;
  1209.     }
  1210.     while (line_buf < endl_buf);
  1211.   }
  1212.   while (line_buf < endl_buf) *line_ptr++ = *line_buf++;
  1213.  
  1214.   do
  1215.   { if (ip->out_vrc == 256)
  1216.       (*ip->raw_encode)(ip);
  1217.     ip->out_vrc++;
  1218.     if (--ip->lines_left <= 0)
  1219.     {
  1220.       (*ip->raw_encode)(ip);
  1221.       ip->pub.pbuf = ip->line_adr;
  1222.       ip->pub.bytes_left = ip->length;
  1223.       (*ip->user_exit)();
  1224.   } }
  1225.   while (--ip->pub.vrc);
  1226.   ip->pub.vrc++;
  1227.  
  1228.   ip->pub.pbuf = ip->line_adr; ip->pub.bytes_left = ip->length;
  1229. }
  1230.  
  1231. static void l_1_p_2_encode(IBUF *ip)
  1232. {
  1233.   char cdata, c_val, *line_buf, *line_ptr, *endl_buf, *start_ptr;
  1234.   FBUFPUB *output;
  1235.   int i;
  1236.  
  1237.   output = ip->output;
  1238.   if (ip->out_vrc != 1)
  1239.   {
  1240.     long limit = 1;
  1241.     ip->temp = *output;
  1242.     switch (ip->out_vrc)
  1243.     {
  1244.       case 2: limit += 2;
  1245.       case 3:
  1246.       case 4: limit += 1;
  1247.     }
  1248.     output->pbuf = ip->pbuf = ip->data - limit;
  1249.     output->bytes_left = limit;
  1250.     output->data_func = put_vrc;
  1251.   }
  1252.   line_ptr = line_buf = ip->pub.pbuf;
  1253.   do
  1254.   { endl_buf = line_buf + ip->byte_width;
  1255.     do
  1256.     { char *line_lim0 = line_buf + 255;
  1257.       if (line_lim0 > endl_buf) line_lim0 = endl_buf;
  1258.       for (;;)
  1259.       {
  1260.     if ((cdata = *line_buf++) == 0 || cdata == -1)
  1261.     {
  1262.       char *line_lim = --line_buf + 127;
  1263.       if (line_lim > endl_buf) line_lim = endl_buf;
  1264.       start_ptr = line_buf;
  1265.       do line_buf++;
  1266.       while (line_buf < line_lim && *line_buf == cdata);
  1267.       i = (int)(line_buf - start_ptr);
  1268.       if (i >= 3 || start_ptr == line_ptr ||
  1269.           line_buf >= line_lim0)
  1270.       {
  1271.         entry:
  1272.         if (start_ptr != line_ptr)
  1273.         {
  1274.           FPUTC(output, 0x80);
  1275.           FPUTC(output, (char)(start_ptr - line_ptr));
  1276.           do FPUTC(output, *line_ptr++);
  1277.           while (line_ptr < start_ptr);
  1278.         }
  1279.         cdata <<= 7; cdata |= (char)i;
  1280.         FPUTC(output, cdata);
  1281.         line_ptr = line_buf; break;
  1282.       }
  1283.       if (i == 2)
  1284.       {
  1285.         char cval2; line_lim = line_buf;
  1286.         for (;;)
  1287.           if ((c_val = *line_lim++) == 0 || c_val == -1)
  1288.           {
  1289.         if (line_lim >= line_lim0) goto entry;
  1290.         if (*line_lim == c_val) goto entry;
  1291.           }
  1292.           else
  1293.           {
  1294.         if (line_lim >= line_lim0 - 2) break;
  1295.         cval2 = *line_lim++;
  1296.         if (c_val != *line_lim++) break;
  1297.         if (cval2 != *line_lim++) break;
  1298.         if (line_lim >= line_lim0) goto entry;
  1299.         if (line_lim < line_lim0 - 1 &&
  1300.             line_lim[0] == c_val &&
  1301.             line_lim[1] == cval2) goto entry;
  1302.       }   }
  1303.       line_buf = start_ptr + 1;
  1304.     }
  1305.     if (line_buf < endl_buf - 2 &&
  1306.         cdata == line_buf[1])
  1307.     {
  1308.       c_val = line_buf[0];
  1309.       if (c_val == line_buf[2])
  1310.       {
  1311.         char *line_lim = --line_buf + 255 * 2;
  1312.         if (line_lim > endl_buf) line_lim = endl_buf;
  1313.         start_ptr = line_buf;
  1314.         --line_lim;
  1315.         do line_buf += 2;
  1316.         while (line_buf < line_lim &&
  1317.            line_buf[0] == cdata &&
  1318.            line_buf[1] == c_val);
  1319.         i = (int)(line_buf - start_ptr) >> 1;
  1320.         if (i >= 3 || start_ptr == line_ptr ||
  1321.         line_buf >= line_lim0)
  1322.         {
  1323.           if (start_ptr != line_ptr)
  1324.           {
  1325.         FPUTC(output, 0x80);
  1326.         FPUTC(output, (char)(start_ptr - line_ptr));
  1327.         do FPUTC(output, *line_ptr++);
  1328.         while (line_ptr < start_ptr);
  1329.           }
  1330.           FPUTC(output, 0);
  1331.           FPUTC(output, (char)i);
  1332.           FPUTC(output, cdata);
  1333.           FPUTC(output, c_val);
  1334.           line_ptr = line_buf; break;
  1335.         }
  1336.         line_buf = start_ptr + 1;
  1337.     } }
  1338.     if (line_buf >= line_lim0)
  1339.     {
  1340.       FPUTC(output, 0x80);
  1341.       FPUTC(output, (char)(line_buf - line_ptr));
  1342.       do FPUTC(output, *line_ptr++);
  1343.       while (line_ptr < line_buf);
  1344.       break;
  1345.     } } }
  1346.     while (line_buf < endl_buf);
  1347.   }
  1348.   while (endl_buf < ip->image_adr);
  1349.  
  1350.   if (--ip->out_vrc)
  1351.   {
  1352.     line_buf = output->pbuf;
  1353.     *output = ip->temp;
  1354.     ++ip->out_vrc;
  1355.     do
  1356.     { line_ptr = ip->pbuf;
  1357.       do FPUTC(output, *line_ptr++);
  1358.       while (line_ptr < line_buf);
  1359.     }
  1360.     while (--ip->out_vrc);
  1361. } }
  1362.  
  1363. static void l_1_p_1_encode(IBUF *ip)
  1364. {
  1365.   char cdata, c_val, *line_buf, *line_ptr, *endl_buf, *start_ptr;
  1366.   FBUFPUB *output;
  1367.   int i;
  1368.  
  1369.   output = ip->output;
  1370.   if (ip->out_vrc != 1)
  1371.   {
  1372.     long limit = 1;
  1373.     ip->temp = *output;
  1374.     switch (ip->out_vrc)
  1375.     {
  1376.       case 2: limit += 2;
  1377.       case 3:
  1378.       case 4: limit += 1;
  1379.     }
  1380.     output->pbuf = ip->pbuf = ip->data - limit;
  1381.     output->bytes_left = limit;
  1382.     output->data_func = put_vrc;
  1383.   }
  1384.   line_ptr = line_buf = ip->pub.pbuf;
  1385.   do
  1386.   { endl_buf = line_buf + ip->byte_width;
  1387.     do
  1388.     { char *line_lim0 = line_buf + 255;
  1389.       if (line_lim0 > endl_buf) line_lim0 = endl_buf;
  1390.       for (;;)
  1391.       {
  1392.     if ((cdata = *line_buf++) == 0 || cdata == -1)
  1393.     {
  1394.       char *line_lim = --line_buf + 127;
  1395.       if (line_lim > endl_buf) line_lim = endl_buf;
  1396.       start_ptr = line_buf;
  1397.       do line_buf++;
  1398.       while (line_buf < line_lim && *line_buf == cdata);
  1399.       i = (int)(line_buf - start_ptr);
  1400.       if (i >= 3 || start_ptr == line_ptr ||
  1401.           line_buf >= line_lim0)
  1402.       {
  1403.         put_solid:
  1404.         if (start_ptr != line_ptr)
  1405.         {
  1406.           FPUTC(output, 0x80);
  1407.           FPUTC(output, (char)(start_ptr - line_ptr));
  1408.           do FPUTC(output, *line_ptr++);
  1409.           while (line_ptr < start_ptr);
  1410.         }
  1411.         cdata <<= 7; cdata |= (char)i;
  1412.         FPUTC(output, cdata);
  1413.         line_ptr = line_buf; break;
  1414.       }
  1415.       if (i == 2)
  1416.       {
  1417.         line_lim = line_buf;
  1418.         for (;;)
  1419.           if ((c_val = *line_lim++) == 0 || c_val == -1)
  1420.           {
  1421.         if (line_lim >= line_lim0) goto put_solid;
  1422.         if (*line_lim == c_val) goto put_solid;
  1423.           }
  1424.           else
  1425.           {
  1426.         if (line_lim >= line_lim0 - 1) break;
  1427.         if (c_val != *line_lim++) break;
  1428.         if (c_val != *line_lim++) break;
  1429.         if (line_lim >= line_lim0) goto put_solid;
  1430.         if (*line_lim == c_val) goto put_solid;
  1431.       }   }
  1432.       line_buf = start_ptr + 1;
  1433.     }
  1434.     if (line_buf < endl_buf - 1 &&
  1435.         cdata == line_buf[0] &&
  1436.         cdata == line_buf[1])
  1437.     {
  1438.       char *line_lim = --line_buf + 255;
  1439.       if (line_lim > endl_buf) line_lim = endl_buf;
  1440.       start_ptr = line_buf;
  1441.       do line_buf++;
  1442.       while (line_buf < line_lim && *line_buf == cdata);
  1443.       i = (int)(line_buf - start_ptr);
  1444.       if (i >= 5 || start_ptr == line_ptr ||
  1445.           line_buf >= line_lim0)
  1446.       {
  1447.         put_pattern:
  1448.         if (start_ptr != line_ptr)
  1449.         {
  1450.           FPUTC(output, 0x80);
  1451.           FPUTC(output, (char)(start_ptr - line_ptr));
  1452.           do FPUTC(output, *line_ptr++);
  1453.           while (line_ptr < start_ptr);
  1454.         }
  1455.         FPUTC(output, 0);
  1456.         FPUTC(output, (char)i);
  1457.         FPUTC(output, cdata);
  1458.         line_ptr = line_buf; break;
  1459.       }
  1460.       if (i == 4)
  1461.       {
  1462.         line_lim = line_buf;
  1463.         for (;;)
  1464.           if ((c_val = *line_lim++) == 0 || c_val == -1)
  1465.           {
  1466.         if (line_lim >= line_lim0) goto put_pattern;
  1467.         if (*line_lim == c_val) goto put_pattern;
  1468.           }
  1469.           else
  1470.           {
  1471.         if (line_lim >= line_lim0 - 1) break;
  1472.         if (c_val != *line_lim++) break;
  1473.         if (c_val != *line_lim++) break;
  1474.         if (line_lim >= line_lim0) goto put_pattern;
  1475.         if (*line_lim == c_val) goto put_pattern;
  1476.       }   }
  1477.       line_buf = start_ptr + 1;
  1478.      }
  1479.     if (line_buf >= line_lim0)
  1480.     {
  1481.       FPUTC(output, 0x80);
  1482.       FPUTC(output, (char)(line_buf - line_ptr));
  1483.       do FPUTC(output, *line_ptr++);
  1484.       while (line_ptr < line_buf);
  1485.       break;
  1486.     } } }
  1487.     while (line_buf < endl_buf);
  1488.   }
  1489.   while (endl_buf < ip->image_adr);
  1490.  
  1491.   if (--ip->out_vrc)
  1492.   {
  1493.     line_buf = output->pbuf;
  1494.     *output = ip->temp;
  1495.     ++ip->out_vrc;
  1496.     do
  1497.     { line_ptr = ip->pbuf;
  1498.       do FPUTC(output, *line_ptr++);
  1499.       while (line_ptr < line_buf);
  1500.     }
  1501.     while (--ip->out_vrc);
  1502. } }
  1503.  
  1504. static void level_1_putline(IBUF *ip)
  1505. {
  1506.   char *line_buf, *line_ptr, *endl_buf;
  1507.  
  1508.   line_buf = ip->line_adr;
  1509.   endl_buf = ip->pub.pbuf;
  1510.   line_ptr = endl_buf;
  1511.  
  1512.   if (ip->out_vrc == 0)
  1513.   {
  1514.     if (ip->pub.bytes_left) return;
  1515.   }
  1516.   else
  1517.   {
  1518.     if (ip->pub.bytes_left)
  1519.     {
  1520.       ip->pub.pbuf += ip->pub.bytes_left;
  1521.       ip->pub.bytes_left = 0;
  1522.       (*ip->raw_encode)(ip);
  1523.       ip->pub.pbuf = ip->line_adr;
  1524.       ip->pub.bytes_left = ip->length;
  1525.       return;
  1526.     }
  1527.     do
  1528.     { if (*line_ptr != *line_buf)
  1529.       {
  1530.     (*ip->raw_encode)(ip);
  1531.     break;
  1532.       }
  1533.       line_ptr++; line_buf++;
  1534.     }
  1535.     while (line_buf < endl_buf);
  1536.   }
  1537.   while (line_buf < endl_buf) *line_ptr++ = *line_buf++;
  1538.  
  1539.   do
  1540.   { if (ip->out_vrc == 255)
  1541.       (*ip->raw_encode)(ip);
  1542.     ip->out_vrc++;
  1543.     if (--ip->lines_left <= 0)
  1544.     {
  1545.       (*ip->raw_encode)(ip);
  1546.       ip->pub.pbuf = ip->line_adr;
  1547.       ip->pub.bytes_left = ip->length;
  1548.       (*ip->user_exit)();
  1549.   } }
  1550.   while (--ip->pub.vrc);
  1551.   ip->pub.vrc++;
  1552.  
  1553.   ip->pub.pbuf = ip->line_adr; ip->pub.bytes_left = ip->length;
  1554. }
  1555.